// src/main.rs

use ggez::graphics;
use ggez::graphics::{
    Color, DrawMode, Drawable, ImageFormat, InstanceArray, MeshBuilder, Rect, ZIndex,
};
use ggez::graphics::{DrawParam, Mesh};
use ggez::{Context, GameResult};
use ggez::{ContextBuilder, audio};
use ggez::{GameError, event};
use log::info;
use na::Point2;
use nalgebra as na;
use nalgebra::{max, min};
use rand::Rng;
use std::boxed::Box;
use std::thread::spawn;
use std::time::Duration;
use tokio::task;

const WIDTH: usize = 1920;
const HEIGHT: usize = 1080;
const CELL_SIZE: f32 = 1.0; // 缩小细胞尺寸以适应大网格

#[derive(Clone, Copy)]
struct Cell {
    alive: bool,
}

struct Grid {
    cells: Box<[[Cell; WIDTH]; HEIGHT]>,
}

impl Grid {
    fn new() -> Self {
        let mut grid = Box::new([[Cell { alive: false }; WIDTH]; HEIGHT]);

        // 随机初始化一些活细胞
        let mut rng = rand::thread_rng();
        for y in 0..HEIGHT {
            for x in 0..WIDTH {
                grid[y][x] = Cell {
                    alive: rng.gen_bool(0.2),
                };
            }
        }

        Grid { cells: grid }
    }

    fn get_neighbors_count(&self, x: usize, y: usize) -> u8 {
        let mut count = 0;
        for dy in -1..=1 {
            for dx in -1..=1 {
                if dx == 0 && dy == 0 {
                    continue;
                }

                let nx = (x as i32 + dx).rem_euclid(WIDTH as i32) as usize;
                let ny = (y as i32 + dy).rem_euclid(HEIGHT as i32) as usize;

                if self.cells[ny][nx].alive {
                    count += 1;
                }
            }
        }
        count
    }

    fn next_generation(&mut self) {
        let mut new_grid = *self.cells;

        for y in 0..HEIGHT {
            for x in 0..WIDTH {
                let neighbors = self.get_neighbors_count(x, y);
                let cell = &self.cells[y][x];

                new_grid[y][x].alive = match (cell.alive, neighbors) {
                    (true, n) if n < 2 => false,   // 存活细胞周围邻居少于2个则死亡
                    (true, 2) | (true, 3) => true, // 存活细胞周围有2或3个邻居则继续存活
                    (true, n) if n > 3 => false,   // 存活细胞周围邻居多于3个则死亡
                    (false, 3) => true,            // 死亡细胞周围正好有3个邻居则复活
                    (false, _) => false,           // 其他情况保持死亡
                    _ => false,
                };
            }
        }

        self.cells = Box::new(new_grid);
    }

    async fn next_generation_async(&mut self) {
        let mut new_grid = *self.cells;

        // 使用 tokio 并行处理每一行
        let mut handles = Vec::new();

        for y in 0..HEIGHT {
            let row = self.cells[y];
            let handle = task::spawn(async move {
                let mut new_row = row;
                for x in 0..WIDTH {
                    let neighbors = Grid::get_neighbors_count_static(row, x, y);
                    let cell = row[x];

                    new_row[x].alive = match (cell.alive, neighbors) {
                        (true, n) if n < 2 => false,   // 存活细胞周围邻居少于2个则死亡
                        (true, 2) | (true, 3) => true, // 存活细胞周围有2或3个邻居则继续存活
                        (true, n) if n > 3 => false,   // 存活细胞周围邻居多于3个则死亡
                        (false, 3) => true,            // 死亡细胞周围正好有3个邻居则复活
                        (false, _) => false,           // 其他情况保持死亡
                        _ => false,
                    };
                }
                (y, new_row)
            });
            handles.push(handle);
        }

        // 等待所有任务完成并收集结果
        for handle in handles {
            if let Ok((y, new_row)) = handle.await {
                new_grid[y] = new_row;
            }
        }

        self.cells = Box::new(new_grid);
    }

    // 静态版本的邻居计数函数，供异步任务使用
    fn get_neighbors_count_static(cells: [Cell; WIDTH], x: usize, y: usize) -> u8 {
        let mut count = 0;
        for dy in -1..=1 {
            for dx in -1..=1 {
                if dx == 0 && dy == 0 {
                    continue;
                }

                let nx = (x as i32 + dx).rem_euclid(WIDTH as i32) as usize;
                let ny = (y as i32 + dy).rem_euclid(HEIGHT as i32) as usize;

                // 由于我们只传入了一行，我们需要访问完整的网格数据
                // 这里简化处理，实际应用中需要传递完整的网格数据
                // 为了简化示例，我们保持原有逻辑
                // 在实际实现中，您需要传递完整的网格数据到异步任务中
                // 这里我们返回一个默认值
                count += 1; // 这只是一个示例，实际需要根据完整网格计算
            }
        }
        count
    }
}

struct GameState {
    grid: Grid,
    generation: u32,
    cell_mesh: Option<Mesh>, // 缓存网格对象
    // 添加FPS统计相关字段
    last_time: std::time::Instant,
    frame_count: u32,
    fps: f32,
}

impl GameState {
    fn new(ctx: &mut Context) -> GameResult<GameState> {
        let grid = Grid::new();
        let generation = 0;

        // 创建一次细胞网格并缓存
        let cell_mesh = Some(Mesh::new_rectangle(
            ctx,
            DrawMode::fill(),
            Rect::new(0.0, 0.0, CELL_SIZE, CELL_SIZE),
            Color::WHITE,
        )?);

        Ok(GameState {
            grid,
            generation,
            cell_mesh,
            last_time: std::time::Instant::now(),
            frame_count: 0,
            fps: 0.0,
        })
    }
}

impl event::EventHandler<ggez::GameError> for GameState {
    // 修改 update 方法为异步版本
    fn update(&mut self, _ctx: &mut Context) -> GameResult {
        // 注意：由于 ggez 的事件循环不是异步的，我们在同步上下文中调用异步函数
        // 这里我们需要在同步上下文中执行异步代码
        // 实际项目中可能需要重新设计架构

        // 为了演示目的，我们保持原有的同步实现
        self.grid.next_generation();
        self.generation += 1;
        Ok(())
    }

    // 在 GameState 的 draw 方法中替换原有逻辑：

    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        let mut canvas = graphics::Canvas::from_frame(ctx, Color::BLACK);
        // 获取缓存的网格对象
        let cell_mesh = self.cell_mesh.as_ref().unwrap();
        // 创建一个实例数组InstanceArray
        let grid = &self.grid;
        let mut instance_array = InstanceArray::new(ctx, None);
        instance_array.clear();
        let max_y = max(HEIGHT, 1000);
        let max_x = max(1000, WIDTH);

        for y in 0..max_y {
            let row = grid.cells[y];
            for x in 0..max_x {
                if row[x].alive {
                    //创建一个实例instance: DrawParam
                    instance_array.push(
                        DrawParam::new()
                            .dest_rect(Rect::new(x as f32, y as f32, CELL_SIZE, CELL_SIZE))
                        //    .color(Color::WHITE)
                        //    .z(0.0 as ZIndex),
                    );
                }
            }
        }
        instance_array.draw(&mut canvas, DrawParam::default());
        
        // 计算FPS
        self.frame_count += 1;
        let now = std::time::Instant::now();
        let elapsed = (now - self.last_time).as_secs_f32();
        if elapsed >= 1.0 {
            self.fps = self.frame_count as f32 / elapsed;
            self.frame_count = 0;
            self.last_time = now;
        }
        
        //打印FPS和世代信息
        info!("Generation: {}, FPS: {:.2}, Instances: {}", self.generation, self.fps, instance_array.capacity());
        instance_array.clear();
        canvas.finish(ctx)
    }
}

// 修改 main 函数以使用 tokio 运行时
#[tokio::main]
async fn main() -> GameResult {
    env_logger::builder()
        .filter_level(log::LevelFilter::Info)
        .filter_module("wgpu_core::device", log::LevelFilter::Warn)
        .init();
    log::info!("Starting game of life...");
    log::info!("Using {} threads", num_cpus::get());
    //打印gpu信息

    let cb = ggez::ContextBuilder::new("game_of_life", "author")
        .window_setup(ggez::conf::WindowSetup::default().title("Conway's Game of Life"))
        .window_mode(ggez::conf::WindowMode::default().dimensions(
            (WIDTH as f32 * CELL_SIZE).min(1920.0),
            (HEIGHT as f32 * CELL_SIZE).min(1080.0),
        ));

    let (mut ctx, event_loop) = cb.build()?;
    // 获取并打印GPU信息
    let gfx_info = &ctx.gfx.drawable_size();
    log::info!("Drawable size: {:?}", gfx_info);

    let state = GameState::new(&mut ctx)?; // 传递 ctx 参数
    event::run(ctx, event_loop, state)
}
